using MultiAgentsClient.ChatDataStructures;
using MultiAgentsServer.Scripts.Shared;
using MultiAgentsShared;
using OpenAI.ObjectModels;
using static MultiAgentsClient.Manager.AgentManager;
using static MultiAgentsClient.Manager.UserInfoManager;
using static MultiAgentsClient.Presentation.AgentHeaderPanelModel;
using static MultiAgentsClient.Presentation.Component.AgentMainPanel;

namespace MultiAgentsClient.Presentation;

public partial record AgentMainPanelModel
{
    private readonly EventBus eventBus;

    public int agentId = 0;
    public List<string> LlmModels = [];
    public IState<string> SelectLlmModel => State.Value(this, () => "");
    public IState<float> Temperature => State.Value(this, () => 1.0f);
    public IListState<ToolCallDisp> ToolCallsList => ListState<ToolCallDisp>.Empty(this);
    public IListState<PresetMessageDisp> PresetMessageList => ListState<PresetMessageDisp>.Empty(this);

    public AgentMainPanelModel()
    {
        eventBus = EventBus.Instance;

        eventBus.Subscribe<FetchUserdataCompletedCommand>(async cmd => { await FetchUserdataCompletedCommandHandler(cmd); });
        eventBus.Subscribe<LoadAgentCompleteCommand>(async cmd => { await LoadAgentCompleteCommandHandler(cmd); });
        eventBus.Subscribe<SaveAgentClick>(async cmd => { await SaveAgentClickHandler(cmd); });
        eventBus.Subscribe<DropMesageCommand>(async cmd => { await DropMesageCommandHandler(cmd); });
        eventBus.Subscribe<GenerateMessageCompleteCommand>(async cmd => { await GenerateMessageCompleteCommandHandler(cmd); });
    }

    public async Task AddMessage()
    {
        IImmutableList<PresetMessageDisp> messagesList = await PresetMessageList;
        await PresetMessageList.AddAsync(new PresetMessageDisp(messagesList.Count, StaticValues.ChatMessageRoles.User, ""));
    }

    public async Task GenerateMessage()
    {
        IImmutableList<PresetMessageDisp> messagesList = await PresetMessageList;
        if (messagesList.Count == 0)
        {
            Debug.LogWindow("至少需要一条消息。");
            return;
        }

        float temperature = await Temperature;
        string? model = await SelectLlmModel;
        if (model == null && LlmModels.Count > 0)
        {
            model = LlmModels[0];
        }
        else if (model == null)
        {
            return;
        }

        eventBus.Publish(new GenerateMessageCommand([.. messagesList], temperature, model));
    }

    public async Task DeleteMessage(int id)
    {
        await PresetMessageList.RemoveAllAsync(match: item => item.Id == id);
    }

    public async Task SwitchRole(int id)
    {
        List<PresetMessageDisp> presetMessageDisps = [.. (await PresetMessageList)];

        await PresetMessageList.UpdateAllAsync(
        match: item => item.Id == id,
        updater: cp =>
        {
            if (cp.Role == StaticValues.ChatMessageRoles.User)
            {
                return new PresetMessageDisp(cp.Id, StaticValues.ChatMessageRoles.Assistant, cp.Message);
            }
            else if (cp.Role == StaticValues.ChatMessageRoles.Assistant)
            {
                return new PresetMessageDisp(cp.Id, StaticValues.ChatMessageRoles.System, cp.Message);
            }
            else
            {
                return new PresetMessageDisp(cp.Id, StaticValues.ChatMessageRoles.User, cp.Message);
            }
        });
    }
    
    public async Task SwitchModel()
    {
        string? currentModel = await SelectLlmModel;
        if (string.IsNullOrEmpty(currentModel))
        {
            await SelectLlmModel.SetAsync(LlmModels[0]);
            return;
        }

        for (int i = 0; i < LlmModels.Count; i++)
        {
            if (LlmModels[i] == currentModel)
            {
                if (i == LlmModels.Count - 1)
                {
                    await SelectLlmModel.SetAsync(LlmModels[0]);
                }
                else
                {
                    await SelectLlmModel.SetAsync(LlmModels[i + 1]);
                }
            }
        }
    }

    #region Command
    public async Task FetchUserdataCompletedCommandHandler(FetchUserdataCompletedCommand cmd)
    {
        LlmModels = cmd.UserData.chatAccessibleLlmModels;
        await SelectLlmModel.SetAsync(LlmModels[0]);

        await ToolCallsList.RemoveAllAsync(match: t => true);
        for (int i = 0; i < ToolSetCollection.ToolSets.Count; i++)
        {
            ToolSetCollection.ToolSet tool = ToolSetCollection.ToolSets[i];
            await ToolCallsList.AddAsync(new ToolCallDisp(i + 1, tool.ToolSetName, false));
        }
    }

    public async Task LoadAgentCompleteCommandHandler(LoadAgentCompleteCommand cmd)
    {
        AgentTemplate agent = cmd.Agent;

        agentId = agent.Id;

        if (LlmModels.Contains(agent.LlmModel))
        {
            await SelectLlmModel.SetAsync(agent.LlmModel);
        }
        else
        {
            await SelectLlmModel.SetAsync(LlmModels.Last());
        }
        
        await Temperature.SetAsync(agent.Temperature);

        List<PresetMessageDisp> messages = [];
        try
        {
            messages = SerializableObjectBase.FromJson<List<PresetMessageDisp>>(agent.PresetMessage);
        }
        catch
        {
            messages = [new PresetMessageDisp(agentId, StaticValues.ChatMessageRoles.User, agent.PresetMessage)];
        }

        await PresetMessageList.RemoveAllAsync(match: item => true);
        for (int i = 0; i < messages.Count; i++)
        {
            PresetMessageDisp message = messages[i];
            await PresetMessageList.AddAsync(message);
        }

        await ToolCallsList.RemoveAllAsync(match: item => true);
        for (int i = 0; i < ToolSetCollection.ToolSets.Count; i++)
        {
            ToolSetCollection.ToolSet tool = ToolSetCollection.ToolSets[i];
            await ToolCallsList.AddAsync(new ToolCallDisp(i + 1, tool.ToolSetName, agent.AllowedTools.Contains(tool.ToolDefinitions.Keys.First().Function.Name)));
        }
    }

    public async Task SaveAgentClickHandler(SaveAgentClick cmd)
    {
        string? llmModel = await SelectLlmModel;
        if (string.IsNullOrEmpty(llmModel))
        {
            Debug.LogWindow("请选择模型");
            return;
        }
        
        if (cmd.AgentName == NameConsts.DefaultAgentName)
        {
            Debug.LogWindow("请更换代理名");
            return;
        }

        List<ToolCallDisp> toolCalls = [.. (await ToolCallsList)];
        List<string> checkedNames = toolCalls
            .Where(tc => tc.IsCheck)
            .Select(tc => tc.Name)
            .ToList();

        List<PresetMessageDisp> messages = [.. (await PresetMessageList)];

        AgentTemplate agent = new()
        {
            Id = agentId,
            Name = cmd.AgentName,
            LlmModel = llmModel,
            Temperature = await Temperature,
            AllowedTools = checkedNames,
            PresetMessage = SerializableObjectBase.ConvertToJson(messages)
        };

        eventBus.Publish(new UpdateAgentCommand(agent));
    }

    public async Task DropMesageCommandHandler(DropMesageCommand cmd)
    {
        await PresetMessageList.Update(updater: cp =>
        {
            PresetMessageDisp fromItem = cp[cmd.FromId];
            PresetMessageDisp toItem = cp[cmd.ToId];

            cp = cp.SetItem(cmd.FromId, new PresetMessageDisp(cmd.FromId, toItem.Role, toItem.Message));
            cp = cp.SetItem(cmd.ToId, new PresetMessageDisp(cmd.ToId, fromItem.Role, fromItem.Message));

            return cp;
        }, default);
    }

    public async Task GenerateMessageCompleteCommandHandler(GenerateMessageCompleteCommand cmd)
    {
        IImmutableList<PresetMessageDisp> messagesList = await PresetMessageList;

        await PresetMessageList.AddAsync(new PresetMessageDisp(messagesList.Count, StaticValues.ChatMessageRoles.Assistant, cmd.ResponseMessage));
    }
    #endregion
}
